package deltax.common.math
{
    import __AS3__.vec.*;
    import flash.geom.*;

    final public class Quaternion extends Object
    {
        public var x:Number = 0;
        public var y:Number = 0;
        public var z:Number = 0;
        public var w:Number = 1;

        public function Quaternion(param1:Number = 0, param2:Number = 0, param3:Number = 0, param4:Number = 1)
        {
            this.x = param1;
            this.y = param2;
            this.z = param3;
            this.w = param4;
            return;
        }// end function

        public function get magnitude() : Number
        {
            return Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z);
        }// end function

        public function multiply(param1:Quaternion, param2:Quaternion) : void
        {
            var _loc_3:* = param1.w;
            var _loc_4:* = param1.x;
            var _loc_5:* = param1.y;
            var _loc_6:* = param1.z;
            var _loc_7:* = param2.w;
            var _loc_8:* = param2.x;
            var _loc_9:* = param2.y;
            var _loc_10:* = param2.z;
            this.w = _loc_3 * _loc_7 - _loc_4 * _loc_8 - _loc_5 * _loc_9 - _loc_6 * _loc_10;
            this.x = _loc_3 * _loc_8 + _loc_4 * _loc_7 + _loc_5 * _loc_10 - _loc_6 * _loc_9;
            this.y = _loc_3 * _loc_9 - _loc_4 * _loc_10 + _loc_5 * _loc_7 + _loc_6 * _loc_8;
            this.z = _loc_3 * _loc_10 + _loc_4 * _loc_9 - _loc_5 * _loc_8 + _loc_6 * _loc_7;
            return;
        }// end function

        public function multiplyVector(param1:Vector3D, param2:Quaternion = null) : Quaternion
        {
            param2 = param2 || new Quaternion();
            var _loc_3:* = param1.x;
            var _loc_4:* = param1.y;
            var _loc_5:* = param1.z;
            param2.w = (-this.x) * _loc_3 - this.y * _loc_4 - this.z * _loc_5;
            param2.x = this.w * _loc_3 + this.y * _loc_5 - this.z * _loc_4;
            param2.y = this.w * _loc_4 - this.x * _loc_5 + this.z * _loc_3;
            param2.z = this.w * _loc_5 + this.x * _loc_4 - this.y * _loc_3;
            return param2;
        }// end function

        public function fromAxisAngle(param1:Vector3D, param2:Number) : void
        {
            var _loc_3:* = Math.sin(param2 / 2);
            var _loc_4:* = Math.cos(param2 / 2);
            this.x = param1.x * _loc_3;
            this.y = param1.y * _loc_3;
            this.z = param1.z * _loc_3;
            this.w = _loc_4;
            this.normalize();
            return;
        }// end function

        public function slerp(param1:Quaternion, param2:Quaternion, param3:Number) : void
        {
            var _loc_13:Number = NaN;
            var _loc_14:Number = NaN;
            var _loc_15:Number = NaN;
            var _loc_16:Number = NaN;
            var _loc_17:Number = NaN;
            var _loc_4:* = param1.w;
            var _loc_5:* = param1.x;
            var _loc_6:* = param1.y;
            var _loc_7:* = param1.z;
            var _loc_8:* = param2.w;
            var _loc_9:* = param2.x;
            var _loc_10:* = param2.y;
            var _loc_11:* = param2.z;
            var _loc_12:* = _loc_4 * _loc_8 + _loc_5 * _loc_9 + _loc_6 * _loc_10 + _loc_7 * _loc_11;
            if (_loc_4 * _loc_8 + _loc_5 * _loc_9 + _loc_6 * _loc_10 + _loc_7 * _loc_11 < 0)
            {
                _loc_12 = -_loc_12;
                _loc_8 = -_loc_8;
                _loc_9 = -_loc_9;
                _loc_10 = -_loc_10;
                _loc_11 = -_loc_11;
            }
            if (_loc_12 < 0.99999)
            {
                _loc_13 = Math.acos(_loc_12);
                _loc_14 = 1 / Math.sin(_loc_13);
                _loc_15 = Math.sin(_loc_13 * (1 - param3)) * _loc_14;
                _loc_16 = Math.sin(_loc_13 * param3) * _loc_14;
                this.w = _loc_4 * _loc_15 + _loc_8 * _loc_16;
                this.x = _loc_5 * _loc_15 + _loc_9 * _loc_16;
                this.y = _loc_6 * _loc_15 + _loc_10 * _loc_16;
                this.z = _loc_7 * _loc_15 + _loc_11 * _loc_16;
            }
            else
            {
                this.w = _loc_4 + param3 * (_loc_8 - _loc_4);
                this.x = _loc_5 + param3 * (_loc_9 - _loc_5);
                this.y = _loc_6 + param3 * (_loc_10 - _loc_6);
                this.z = _loc_7 + param3 * (_loc_11 - _loc_7);
                _loc_17 = 1 / Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z);
                this.w = this.w * _loc_17;
                this.x = this.x * _loc_17;
                this.y = this.y * _loc_17;
                this.z = this.z * _loc_17;
            }
            return;
        }// end function

        public function lerp(param1:Quaternion, param2:Quaternion, param3:Number) : void
        {
            var _loc_12:Number = NaN;
            var _loc_4:* = param1.w;
            var _loc_5:* = param1.x;
            var _loc_6:* = param1.y;
            var _loc_7:* = param1.z;
            var _loc_8:* = param2.w;
            var _loc_9:* = param2.x;
            var _loc_10:* = param2.y;
            var _loc_11:* = param2.z;
            if (_loc_4 * _loc_8 + _loc_5 * _loc_9 + _loc_6 * _loc_10 + _loc_7 * _loc_11 < 0)
            {
                _loc_8 = -_loc_8;
                _loc_9 = -_loc_9;
                _loc_10 = -_loc_10;
                _loc_11 = -_loc_11;
            }
            this.w = _loc_4 + param3 * (_loc_8 - _loc_4);
            this.x = _loc_5 + param3 * (_loc_9 - _loc_5);
            this.y = _loc_6 + param3 * (_loc_10 - _loc_6);
            this.z = _loc_7 + param3 * (_loc_11 - _loc_7);
            _loc_12 = 1 / Math.sqrt(this.w * this.w + this.x * this.x + this.y * this.y + this.z * this.z);
            this.w = this.w * _loc_12;
            this.x = this.x * _loc_12;
            this.y = this.y * _loc_12;
            this.z = this.z * _loc_12;
            return;
        }// end function

        public function fromEulerAngles(param1:Number, param2:Number, param3:Number) : void
        {
            var _loc_4:* = param1 * 0.5;
            var _loc_5:* = param2 * 0.5;
            var _loc_6:* = param3 * 0.5;
            var _loc_7:* = Math.cos(_loc_4);
            var _loc_8:* = Math.sin(_loc_4);
            var _loc_9:* = Math.cos(_loc_5);
            var _loc_10:* = Math.sin(_loc_5);
            var _loc_11:* = Math.cos(_loc_6);
            var _loc_12:* = Math.sin(_loc_6);
            this.w = _loc_7 * _loc_9 * _loc_11 + _loc_8 * _loc_10 * _loc_12;
            this.x = _loc_8 * _loc_9 * _loc_11 - _loc_7 * _loc_10 * _loc_12;
            this.y = _loc_7 * _loc_10 * _loc_11 + _loc_8 * _loc_9 * _loc_12;
            this.z = _loc_7 * _loc_9 * _loc_12 - _loc_8 * _loc_10 * _loc_11;
            return;
        }// end function

        public function toEulerAngles(param1:Vector3D = null) : Vector3D
        {
            param1 = param1 || new Vector3D();
            param1.x = Math.atan2(2 * (this.w * this.x + this.y * this.z), 1 - 2 * (this.x * this.x + this.y * this.y));
            param1.y = Math.asin(2 * (this.w * this.y - this.z * this.x));
            param1.z = Math.atan2(2 * (this.w * this.z + this.x * this.y), 1 - 2 * (this.y * this.y + this.z * this.z));
            return param1;
        }// end function

        public function normalize(param1:Number = 1) : void
        {
            var _loc_2:* = param1 / Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
            this.x = this.x * _loc_2;
            this.y = this.y * _loc_2;
            this.z = this.z * _loc_2;
            this.w = this.w * _loc_2;
            return;
        }// end function

        public function toString() : String
        {
            return "{x:" + this.x + " y:" + this.y + " z:" + this.z + " w:" + this.w + "}";
        }// end function

        public function toMatrix3D(param1:Matrix3D = null) : Matrix3D
        {
            var _loc_2:* = Matrix3DUtils.RAW_DATA_CONTAINER;
            var _loc_3:* = this.x + this.x;
            var _loc_4:* = this.y + this.y;
            var _loc_5:* = this.z + this.z;
            var _loc_6:* = this.x * _loc_3;
            var _loc_7:* = this.x * _loc_4;
            var _loc_8:* = this.x * _loc_5;
            var _loc_9:* = this.y * _loc_4;
            var _loc_10:* = this.y * _loc_5;
            var _loc_11:* = this.z * _loc_5;
            var _loc_12:* = this.w * _loc_3;
            var _loc_13:* = this.w * _loc_4;
            var _loc_14:* = this.w * _loc_5;
            _loc_2[0] = 1 - (_loc_9 + _loc_11);
            _loc_2[1] = _loc_7 + _loc_14;
            _loc_2[2] = _loc_8 - _loc_13;
            _loc_2[3] = 0;
            _loc_2[4] = _loc_7 - _loc_14;
            _loc_2[5] = 1 - (_loc_6 + _loc_11);
            _loc_2[6] = _loc_10 + _loc_12;
            _loc_2[7] = 0;
            _loc_2[8] = _loc_8 + _loc_13;
            _loc_2[9] = _loc_10 - _loc_12;
            _loc_2[10] = 1 - (_loc_6 + _loc_9);
            _loc_2[11] = 0;
            _loc_2[12] = 0;
            _loc_2[13] = 0;
            _loc_2[14] = 0;
            _loc_2[15] = 1;
            if (!param1)
            {
                return new Matrix3D(_loc_2);
            }
            param1.copyRawDataFrom(_loc_2);
            return param1;
        }// end function

        public function fromMatrix(param1:Matrix3D) : void
        {
            var _loc_2:* = param1.decompose(Orientation3D.QUATERNION)[1];
            this.x = _loc_2.x;
            this.y = _loc_2.y;
            this.z = _loc_2.z;
            this.w = _loc_2.w;
            return;
        }// end function

        public function toRawData(param1:Vector.<Number>, param2:Boolean = false) : void
        {
            var _loc_3:* = 2 * this.x * this.y;
            var _loc_4:* = 2 * this.x * this.z;
            var _loc_5:* = 2 * this.x * this.w;
            var _loc_6:* = 2 * this.y * this.z;
            var _loc_7:* = 2 * this.y * this.w;
            var _loc_8:* = 2 * this.z * this.w;
            var _loc_9:* = this.x * this.x;
            var _loc_10:* = this.y * this.y;
            var _loc_11:* = this.z * this.z;
            var _loc_12:* = this.w * this.w;
            param1[0] = _loc_9 - _loc_10 - _loc_11 + _loc_12;
            param1[1] = _loc_3 - _loc_8;
            param1[2] = _loc_4 + _loc_7;
            param1[4] = _loc_3 + _loc_8;
            param1[5] = -_loc_9 + _loc_10 - _loc_11 + _loc_12;
            param1[6] = _loc_6 - _loc_5;
            param1[8] = _loc_4 - _loc_7;
            param1[9] = _loc_6 + _loc_5;
            param1[10] = -_loc_9 - _loc_10 + _loc_11 + _loc_12;
            var _loc_13:int = 0;
            param1[11] = 0;
            var _loc_13:* = _loc_13;
            param1[7] = _loc_13;
            param1[3] = _loc_13;
            if (!param2)
            {
                var _loc_13:int = 0;
                param1[14] = 0;
                var _loc_13:* = _loc_13;
                param1[13] = _loc_13;
                param1[12] = _loc_13;
                param1[15] = 1;
            }
            return;
        }// end function

        public function clone() : Quaternion
        {
            return new Quaternion(this.x, this.y, this.z, this.w);
        }// end function

        public function rotatePoint(param1:Vector3D, param2:Vector3D = null) : Vector3D
        {
            var _loc_3:Number = NaN;
            var _loc_4:Number = NaN;
            var _loc_5:Number = NaN;
            var _loc_6:Number = NaN;
            var _loc_7:* = param1.x;
            var _loc_8:* = param1.y;
            var _loc_9:* = param1.z;
            param2 = param2 || new Vector3D();
            _loc_6 = (-this.x) * _loc_7 - this.y * _loc_8 - this.z * _loc_9;
            _loc_3 = this.w * _loc_7 + this.y * _loc_9 - this.z * _loc_8;
            _loc_4 = this.w * _loc_8 - this.x * _loc_9 + this.z * _loc_7;
            _loc_5 = this.w * _loc_9 + this.x * _loc_8 - this.y * _loc_7;
            param2.x = (-_loc_6) * this.x + _loc_3 * this.w - _loc_4 * this.z + _loc_5 * this.y;
            param2.y = (-_loc_6) * this.y + _loc_3 * this.z + _loc_4 * this.w - _loc_5 * this.x;
            param2.z = (-_loc_6) * this.z - _loc_3 * this.y + _loc_4 * this.x + _loc_5 * this.w;
            return param2;
        }// end function

        public function copyFrom(param1:Quaternion) : void
        {
            this.x = param1.x;
            this.y = param1.y;
            this.z = param1.z;
            this.w = param1.w;
            return;
        }// end function

        public function get isIdentity() : Boolean
        {
            return this.x == 0 && this.y == 0 && this.z == 0 && this.w == 1;
        }// end function

    }
}
